package main

import (
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"Projects/CavaOpenAPI/internal/business"
	Mycontext "Projects/CavaOpenAPI/internal/context"
	"Projects/CavaOpenAPI/internal/db"
	"Projects/CavaOpenAPI/internal/qfcfg"
	"Projects/CavaOpenAPI/internal/redis"

	"github.com/kataras/iris/v12"
	"github.com/kataras/iris/v12/context"
	"github.com/qf-tech/qftech-base/pkg/log"
	qflog "github.com/qf-tech/qftech-base/pkg/log"
	"github.com/qf-tech/qftech-base/pkg/qfcrypt"
)

// middleWare def
func middleWare(c iris.Context) {
	start := time.Now()
	h := business.Controller{}
	h.CheckTraceID(c)
	log := qflog.GetLogger().GetCtx(c.Request().Context()).Sugar()
	c.Next()
	// 统计时间
	since := time.Since(start)
	log.Infof("cost: %v", since)
}

// Cors 跨域请求处理
func Cors(ctx iris.Context) {
	ctx.Header("Access-Control-Allow-Origin", "*")
	if ctx.Request().Method == "OPTIONS" {
		ctx.Header("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,PATCH,OPTIONS")
		ctx.Header("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization")
		ctx.StatusCode(204)
		return
	}
	ctx.Next()
}

func newRouter() *iris.Application {
	app := iris.New()
	// app.Use(iris.Logger())
	// app.Use(app.Recovery())

	app.ContextPool.Attach(func() iris.Context {
		return &Mycontext.Context{
			// If you use the embedded Context,
			// call the `context.NewContext` to create one:
			Context: context.NewContext(app),
		}
	})

	// 注册中间件
	app.Use(Cors)
	app.Use(middleWare)

	h := business.Controller{}
	api := app.Party("/")
	{
		api.Post("/api/secret/refresh", h.SecretFresh)
		api.Get("/api/token/get", h.AccessTokenGet)
		api.Get("/api/token/check", h.PreCheckToken, h.CheckToken)
		api.Post("/api/task/create", h.PreCheckToken, h.CreateTask)
		api.Post("/cava3/upload", h.PreCheckToken, h.AddXWsse, h.ProxyHandler)
		api.Get("/api/dev/teu/list", h.PreCheckToken, h.SmuProxyHandler)

		// 往 CavaSvrProxy 纯转发的路由
		for _, data := range qfcfg.ServerConfig.Client.ProxyUri {
			uris := strings.Split(data, " ")
			if len(uris) != 2 {
				continue
			}

			switch uris[0] {
			case "GET":
				api.Get(uris[1], h.PreCheckToken, h.ProxyHandler)
				log.Sugare.Infof("uri registered, uri: %s", data)
			case "POST":
				api.Post(uris[1], h.PreCheckToken, h.ProxyHandler)
				log.Sugare.Infof("uri registered, uri: %s", data)
			default:
				log.Sugare.Errorf("invalid uri, uri: %s", data)
			}
		}
	}

	return app
}

func initCrypt() {
	currentVersionFlag := "QFTECH"
	key := "lmN4dtPyeC5r29DYBLl0P0OoA4Afy/2UnCg0zd+hHhg="

	oldKeys := make(map[string][]byte)
	zeroKeytr := "q_1dY=Khec2nMNxV"
	oldKeys[qfcrypt.ZeroVersionFlag] = []byte(zeroKeytr)

	_ = qfcrypt.Init(currentVersionFlag, []byte(key), oldKeys)
}

func initRedis() error {
	r := qfcfg.ServerConfig.Redis
	config := redis.Config{
		Password: r.Password.Value,
		Host:     r.Host,
		Port:     r.Port,
	}
	return redis.InitRedisPool(config)
}

func initDB() error {
	m := qfcfg.ServerConfig.Mysql
	config := db.DBConfig{
		Username: m.Username,
		Password: m.Password.Value,
		Host:     m.Host,
		Port:     m.Port,
		DBName:   m.Dbname,
	}
	return db.Init(config)
}

func httpServer() {
	client := qfcfg.ServerConfig.Client
	address := fmt.Sprintf("%s:%d", client.IP, client.Port)

	router := newRouter()
	err := router.Run(iris.Addr(address))
	if err != nil {
		qflog.Sugare.Errorf("listen err: %v", err)
		os.Exit(1)
	}
}

func main() {
	qflog.Init(nil)
	initCrypt()
	qfcfg.InitConfig()

	// 打印版本信息
	path, _ := os.Executable()
	_, svrName := filepath.Split(path)
	flag.Parse()
	if option.PrintVersion {
		fmt.Printf("%s %s %s (Git SHA: %s, Go Version: %s, BuildAt: %s)\n", svrName, GitBranch, Version, GitSHA, runtime.Version(), BuildAt)
		os.Exit(0)
	}

	var demo business.Controller
	demo.Init()

	if err := initRedis(); err != nil {
		log.Sugare.Errorf("redis init failed, err: %v", err)
		return
	}

	if err := initDB(); err != nil {
		log.Sugare.Errorf("mysql init failed, err: %v", err)
		return
	}

	go httpServer()
	fmt.Println("cava client start.")

	for {
		demo.Start()
		// 重试间隔必须大于心跳周期
		time.Sleep(60 * time.Second)
	}
}
